home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 001 / fue / c / MAIN < prev    next >
Text File  |  1991-06-01  |  33KB  |  1,029 lines

  1. /*
  2.  *      MicroEMACS 3.10
  3.  *              written by Daniel M. Lawrence
  4.  *              based on code by Dave G. Conroy.
  5.  *
  6.  *      (C)opyright 1988,1989 by Daniel M. Lawrence
  7.  *      MicroEMACS 3.10 can be copied and distributed freely for any
  8.  *      non-commercial purposes. MicroEMACS 3.10 can only be incorporated
  9.  *      into commercial software with the permission of the current author.
  10.  *
  11.  * This file contains the main driving routine, and some keyboard processing
  12.  * code, for the MicroEMACS screen editor.
  13.  *
  14.  */
  15.  
  16. /*      Modifications:
  17.         13-Sep-89       Mike Burrow (INMOS)     Added folding.
  18. */
  19.  
  20.  
  21. /*{{{  include files*/
  22. #include        <stdio.h>
  23.  
  24. /* make global definitions not external */
  25. #define maindef
  26.  
  27. #include        "estruct.h"     /* global structures and defines */
  28. #include        "etype.h"       /* variable prototype definitions */
  29. #include        "efunc.h"       /* function declarations and name table */
  30. #include        "edef.h"        /* global definitions */
  31. #include        "elang.h"       /* human language definitions */
  32. #include        "ebind.h"       /* default key bindings */
  33. #include        "efolding.h"    /* default fold markers */
  34. /*}}}*/
  35.  
  36. /*{{{  machine specifics - stack size increase etc*/
  37. /* for many different systems, increase the default stack space */
  38.  
  39. #if     MSDOS & LATTICE
  40. unsigned _stack = 20000;
  41. #endif
  42.  
  43. #if     MSDOS & DTL
  44. int     _okbigbuf = 0;          /* Only allocate memory when needed.*/
  45. int     _stack = 20000;         /* Reset the ol' stack size.*/
  46. #endif
  47.  
  48. #if     ATARI & MWC
  49. long _stksize = 20000L;         /* reset stack size (must be even) */
  50. #endif
  51.  
  52. #if     MSDOS & AZTEC
  53. int _STKSIZ = 20000/16;         /* stack size in paragraphs */
  54. int _STKRED = 1024;             /* stack checking limit */
  55. int _HEAPSIZ = 4096/16;         /* (in paragraphs) */
  56. /*int _STKLOW = 0;              default is stack above heap (small only) */
  57. #endif
  58.  
  59. #if     MSDOS & TURBO
  60. extern unsigned int _stklen = 10000;
  61. #endif
  62.  
  63. /*      make VMS happy...       */
  64.  
  65. #if     VMS
  66. #include        <ssdef.h>
  67. #define GOOD    (SS$_NORMAL)
  68. #endif
  69.  
  70. #ifndef GOOD
  71. #define GOOD    0
  72. #endif
  73. /*}}}*/
  74.  
  75. /*
  76.         This is the primary entry point that is used by command line
  77.         invocation, and by applications that link with microemacs in
  78.         such a way that each invocation of Emacs is a fresh environment.
  79.  
  80.         There is another entry point in VMS.C that is used when
  81.         microemacs is "linked" (In quotes, because it is a run-time link
  82.         rather than a link-time link.) with applications that wish Emacs
  83.         to preserve it's context across invocations.  (For example,
  84.         EMACS.RC is only executed once per invocation of the
  85.         application, instead of once per invocation of Emacs.)
  86.  
  87.         Note that re-entering an Emacs that is saved in a kept
  88.         subprocess would require a similar entrypoint.
  89. */
  90.  
  91. #if     CALLED
  92. emacs(argc, argv)
  93. #else
  94. main(argc, argv)
  95. #endif
  96.  
  97. int argc;       /* # of arguments */
  98. char *argv[];   /* argument strings */
  99.  
  100. {
  101.         register int status;
  102.  
  103.         /* Initialize the editor */
  104.         eexitflag = FALSE;
  105.         vtinit();               /* Terminal */
  106.         if (eexitflag)
  107.                 goto abortrun;
  108.         edinit("main");         /* Buffers, windows */
  109.         varinit();              /* user variables */
  110.         initchars();            /* character set definitions */
  111.         initlinelist();         /* fold line list. MJB: 15-Sep-89 */
  112.         initfoldstrings();      /* default fold markers. BG: 11-Oct-89 */
  113.         
  114.         /* Process the command line and let the user edit */
  115.         dcline(argc, argv);
  116.         status = editloop();
  117. abortrun:
  118.         vttidy();
  119. #if     CLEAN
  120.         clean();
  121. #endif
  122. #if     CALLED
  123.         return(status);
  124. #else
  125.         exit(status);
  126. #endif
  127. }
  128.  
  129. #if     CLEAN
  130.  
  131. /*{{{  PASCAL NEAR clean()*/
  132. PASCAL NEAR clean()
  133.  
  134. /*
  135.         On some primitive operation systems, and when emacs is used as
  136.         a subprogram to a larger project, emacs needs to de-alloc its
  137.         own used memory, otherwise we just exit.
  138. */
  139.  
  140. {
  141.         register BUFFER *bp;    /* buffer list pointer */
  142.         register WINDOW *wp;    /* window list pointer */
  143.         register WINDOW *tp;    /* temporary window pointer */
  144.  
  145.         /* first clean up the windows */
  146.         wp = wheadp;
  147.         while (wp) {
  148.                 tp = wp->w_wndp;
  149.                 free(wp);
  150.                 wp = tp;
  151.         }
  152.         wheadp = NULL;
  153.  
  154.         /* then the buffers */
  155.         bp = bheadp;
  156.         while (bp) {
  157.                 bp->b_nwnd = 0;
  158.                 bp->b_flag = 0; /* don't say anything about a changed buffer! */
  159.                 zotbuf(bp);
  160.                 bp = bheadp;
  161.         }
  162.  
  163.         /* and the kill buffer */
  164.         kdelete();
  165.  
  166.         /* clear some search variables */
  167. #if     MAGIC
  168.         mcclear();
  169.         rmcclear();
  170. #endif
  171.         if (patmatch != NULL) {
  172.                 free(patmatch);
  173.                 patmatch = NULL;
  174.         }
  175.  
  176.         /* dealloc the user variables */
  177.         varclean();
  178.  
  179.         /* and the video buffers */
  180.         vtfree();
  181. }
  182. /*}}}*/
  183.  
  184. #endif
  185.  
  186. /*      Process a command line.   May be called any time.       */
  187.  
  188. /*{{{  PASCAL NEAR dcline(argc, argv)*/
  189. PASCAL NEAR dcline(argc, argv)
  190.  
  191. int argc;
  192. char *argv[];
  193.  
  194. {
  195.         register BUFFER *bp;            /* temp buffer pointer */
  196.         register int    firstfile;      /* first file flag */
  197.         register int    carg;           /* current arg to scan */
  198.         register int    startflag;      /* startup executed flag */
  199.         BUFFER *firstbp = NULL;         /* ptr to first buffer in cmd line */
  200.         int viewflag;                   /* are we starting in view mode? */
  201.         int gotoflag;                   /* do we need to goto a line at start? */
  202.         int gline;                      /* if so, what line? */
  203.         int searchflag;                 /* Do we need to search at start? */
  204.         int errflag;                    /* C error processing? */
  205.         int infoflag;                   /* display emacs.inf? */
  206.         VDESC vd;                       /* variable num/type */
  207.         char bname[NBUFN];              /* buffer name of file to read */
  208.  
  209. #if     CRYPT
  210.         int cryptflag;                  /* encrypting on the way in? */
  211.         char ekey[NPAT];                /* startup encryption key */
  212. #endif
  213.         CONST NOSHARE extern *pathname[];       /* startup file path/name array */
  214.  
  215.         viewflag = FALSE;       /* view mode defaults off in command line */
  216.         gotoflag = FALSE;       /* set to off to begin with */
  217.         searchflag = FALSE;     /* set to off to begin with */
  218.         firstfile = TRUE;       /* no file to edit yet */
  219.         startflag = FALSE;      /* startup file not executed yet */
  220.         errflag = FALSE;        /* not doing C error parsing */
  221.         infoflag = TRUE;        /* display emacs.inf */
  222. #if     CRYPT
  223.         cryptflag = FALSE;      /* no encryption by default */
  224. #endif
  225.         /* Parse a command line */
  226.         for (carg = 1; carg < argc; ++carg) {
  227.  
  228.                 /* Process Switches */
  229. #if WMCS
  230.                 if (argv[carg][0] == ':') {
  231. #else
  232.                 if (argv[carg][0] == '-') {
  233. #endif
  234.                         switch (argv[carg][1]) {
  235.                                 /* Process Startup macroes */
  236.                                 case 'c':       /* -c for changable file */
  237.                                 case 'C':
  238.                                         viewflag = FALSE;
  239.                                         break;
  240.                                 case 'e':       /* -e process error file */
  241.                                 case 'E':
  242.                                         errflag = TRUE;
  243.                                         break;
  244.                                 case 'g':       /* -g for initial goto */
  245.                                 case 'G':
  246.                                         gotoflag = TRUE;
  247.                                         gline = asc_int(&argv[carg][2]);
  248.                                         break;
  249.                                 case 'i':       /* -i<var> <value> set an initial */
  250.                                 case 'I':       /* value for a variable */
  251.                                         bytecopy(bname, &argv[carg][2], NVSIZE);
  252.                                         findvar(bname, &vd, NVSIZE + 1);
  253.                                         if (vd.v_type == -1) {
  254.                                                 mlwrite(TEXT52, bname);
  255. /*                                                      "%%No such variable as '%s'" */
  256.                                                 break;
  257.                                         }
  258.                                         svar(&vd, argv[++carg]);
  259.                                         break;
  260. #if     CRYPT
  261.                                 case 'k':       /* -k<key> for code key */
  262.                                 case 'K':
  263.                                         cryptflag = TRUE;
  264.                                         strcpy(ekey, &argv[carg][2]);
  265.                                         break;
  266. #endif
  267.                                 case 'n':       /* -n No information */
  268.                                 case 'N':
  269.                                         infoflag = FALSE;
  270.                                         break;
  271.                                 case 'r':       /* -r restrictive use */
  272.                                 case 'R':
  273.                                         restflag = TRUE;
  274.                                         break;
  275.                                 case 's':       /* -s for initial search string */
  276.                                 case 'S':
  277.                                         searchflag = TRUE;
  278.                                         bytecopy(pat,&argv[carg][2],NPAT);
  279.                                         setjtable(pat);
  280.                                         break;
  281.                                 case 'v':       /* -v for View File */
  282.                                 case 'V':
  283.                                         viewflag = TRUE;
  284.                                         break;
  285.                                 default:        /* unknown switch */
  286.                                         /* ignore this for now */
  287.                                         break;
  288.                         }
  289.  
  290.                 } else if (argv[carg][0]== '@') {
  291.  
  292.                         /* Process Startup macroes */
  293.                         if (startup(&argv[carg][1]) == TRUE)
  294.                                 /* don't execute emacs.rc */
  295.                                 startflag = TRUE;
  296.  
  297.                 } else {
  298.  
  299.                         /* Process an input file */
  300.  
  301.                         /* set up a buffer for this file */
  302.                         makename(bname, argv[carg]);
  303.                         unqname(bname);
  304.  
  305.                         /* set this to inactive */
  306.                         bp = bfind(bname, TRUE, 0);
  307.                         strcpy(bp->b_fname, argv[carg]);
  308.                         bp->b_active = FALSE;
  309.                         if (firstfile) {
  310.                                 firstbp = bp;
  311.                                 firstfile = FALSE;
  312.                         }
  313.  
  314.                         /* set the modes appropriatly */
  315.                         if (viewflag)
  316.                                 bp->b_mode |= MDVIEW;
  317. #if     CRYPT
  318.                         if (cryptflag) {
  319.                                 bp->b_mode |= MDCRYPT;
  320.                                 crypt((char *)NULL, 0);
  321.                                 crypt(ekey, strlen(ekey));
  322.                                 bytecopy(bp->b_key, ekey, NPAT);
  323.                         }
  324. #endif
  325.                 }
  326.         }
  327.  
  328.         /* if we are C error parsing... run it! */
  329.         if (errflag) {
  330.                 if (startup("error.cmd") == TRUE)
  331.                         startflag = TRUE;
  332.         }
  333.  
  334.         /* if invoked with no other startup files,
  335.            run the system startup file here */
  336.         if (startflag == FALSE)
  337.                 startup("");
  338.  
  339.         /* if there are any files to read, read the first one! */
  340.         bp = bfind("main", FALSE, 0);
  341.         if (firstfile == FALSE && (gflags & GFREAD)) {
  342.                 swbuffer(firstbp);
  343.                 curbp->b_mode |= gmode;
  344.                 update(TRUE);
  345.                 mlwrite(lastmesg);
  346.                 zotbuf(bp);
  347.         } else
  348.                 bp->b_mode |= gmode;
  349.  
  350.         /* Deal with startup gotos and searches */
  351.         if (gotoflag && searchflag) {
  352.                 update(FALSE);
  353.                 mlwrite(TEXT101);
  354. /*                      "[Can not search and goto at the same time!]" */
  355.         }
  356.         else if (gotoflag) {
  357.                 if (gotoline(TRUE,gline) == FALSE) {
  358.                         update(FALSE);
  359.                         mlwrite(TEXT102);
  360. /*                              "[Bogus goto argument]" */
  361.                 }
  362.         } else if (searchflag) {
  363.                 if (forwhunt(FALSE, 0) == FALSE)
  364.                         update(FALSE);
  365.         }
  366.         if (infoflag)
  367.                 betawarning();
  368. }
  369. /*}}}*/
  370.  
  371. /*
  372.         This is called to let the user edit something.  Note that if you
  373.         arrange to be able to call this from a macro, you will have
  374.         invented the "recursive-edit" function.
  375. */
  376.  
  377. /*{{{  PASCAL NEAR editloop()*/
  378. PASCAL NEAR editloop()
  379. {
  380.         register int c;                 /* command character */
  381.         register int f;         /* default flag */
  382.         register int n;         /* numeric repeat count */
  383.         register int mflag;     /* negative flag on repeat */
  384.         register int basec;     /* c stripped of meta character */
  385.         register int oldflag;   /* old last flag value */
  386.  
  387.         /* setup to process commands */
  388.         lastflag = 0;           /* Fake last flags.     */
  389.  
  390. loop:
  391.         /* if we were called as a subroutine and want to leave, do so */
  392.         if (eexitflag)
  393.                 return(eexitval);
  394.  
  395.         /* execute the "command" macro...normally null */
  396.         oldflag = lastflag;     /* preserve lastflag through this */
  397.         execkey(&cmdhook, FALSE, 1);
  398.         lastflag = oldflag;
  399.  
  400.         /* Fix up the screen    */
  401.         update(FALSE);
  402.  
  403.         /* get the next command from the keyboard */
  404.         c = getkey();
  405.  
  406.         /* if there is something on the command line, clear it */
  407.         if (mpresf != FALSE) {
  408.                 mlerase();
  409.                 update(FALSE);
  410. #if     CLRMSG
  411.                 if (c == ' ')                   /* ITS EMACS does this  */
  412.                         goto loop;
  413. #endif
  414.         }
  415.  
  416.         /* override the arguments if prefixed */
  417.         if (prefix) {
  418.                 if (islower(c & 255))
  419.                         c = (c & ~255) | upperc(c & 255);
  420.                 c |= prefix;
  421.                 f = predef;
  422.                 n = prenum;
  423.                 prefix = 0;
  424.         } else {
  425.                 f = FALSE;
  426.                 n = 1;
  427.         }
  428.  
  429.         /* do META-# processing if needed */
  430.  
  431.         basec = c & ~META;              /* strip meta char off if there */
  432.         if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-') &&
  433.             (getbind(c) == NULL)) {
  434.                 f = TRUE;               /* there is a # arg */
  435.                 n = 0;                  /* start with a zero default */
  436.                 mflag = 1;              /* current minus flag */
  437.                 c = basec;              /* strip the META */
  438.                 while ((c >= '0' && c <= '9') || (c == '-')) {
  439.                         if (c == '-') {
  440.                                 /* already hit a minus or digit? */
  441.                                 if ((mflag == -1) || (n != 0))
  442.                                         break;
  443.                                 mflag = -1;
  444.                         } else {
  445.                                 n = n * 10 + (c - '0');
  446.                         }
  447.                         if ((n == 0) && (mflag == -1))  /* lonely - */
  448.                                 mlwrite("Arg:");
  449.                         else
  450.                                 mlwrite("Arg: %d",n * mflag);
  451.  
  452.                         c = getkey();   /* get the next key */
  453.                 }
  454.                 n = n * mflag;  /* figure in the sign */
  455.         }
  456.  
  457.         /* do ^U repeat argument processing */
  458.  
  459.         if (c == reptc) {                  /* ^U, start argument   */
  460.                 f = TRUE;
  461.                 n = 4;                          /* with argument of 4 */
  462.                 mflag = 0;                      /* that can be discarded. */
  463.                 mlwrite("Arg: 4");
  464.                 while ((c=getkey()) >='0' && c<='9' || c==reptc || c=='-') {
  465.                         if (c == reptc)
  466.                                 if ((n > 0) == ((n*4) > 0))
  467.                                         n = n*4;
  468.                                 else
  469.                                         n = 1;
  470.                         /*
  471.                          * If dash, and start of argument string, set arg.
  472.                          * to -1.  Otherwise, insert it.
  473.                          */
  474.                         else if (c == '-') {
  475.                                 if (mflag)
  476.                                         break;
  477.                                 n = 0;
  478.                                 mflag = -1;
  479.                         }
  480.                         /*
  481.                          * If first digit entered, replace previous argument
  482.                          * with digit and set sign.  Otherwise, append to arg.
  483.                          */
  484.                         else {
  485.                                 if (!mflag) {
  486.                                         n = 0;
  487.                                         mflag = 1;
  488.                                 }
  489.                                 n = 10*n + c - '0';
  490.                         }
  491.                         mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
  492.                 }
  493.                 /*
  494.                  * Make arguments preceded by a minus sign negative and change
  495.                  * the special argument "^U -" to an effective "^U -1".
  496.                  */
  497.                 if (mflag == -1) {
  498.                         if (n == 0)
  499.                                 n++;
  500.                         n = -n;
  501.                 }
  502.         }
  503.  
  504.         /* and execute the command */
  505.         execute(c, f, n);
  506.         goto loop;
  507. }
  508. /*}}}*/
  509.  
  510. /*
  511.  * Initialize all of the buffers and windows. The buffer name is passed down
  512.  * as an argument, because the main routine may have been told to read in a
  513.  * file by default, and we want the buffer name to be right.
  514.  */
  515.  
  516. /*{{{  PASCAL NEAR edinit(bname)*/
  517. PASCAL NEAR edinit(bname)
  518.  
  519. char bname[];   /* name of buffer to initialize */
  520.  
  521. {
  522.         register BUFFER *bp;
  523.         register WINDOW *wp;
  524.         int cmark;              /* current mark */
  525.  
  526.         /* initialize some important globals */
  527.  
  528.         readhook.k_ptr.fp = nullproc;   /* set internal hooks to OFF */
  529.         readhook.k_type = BINDFNC;
  530.         wraphook.k_ptr.fp = wrapword;
  531.         wraphook.k_type = BINDFNC;
  532.         cmdhook.k_ptr.fp = nullproc;
  533.         cmdhook.k_type = BINDFNC;
  534.         writehook.k_ptr.fp = nullproc;
  535.         writehook.k_type = BINDFNC;
  536.         bufhook.k_ptr.fp = nullproc;
  537.         bufhook.k_type = BINDFNC;
  538.         exbhook.k_ptr.fp = nullproc;
  539.         exbhook.k_type = BINDFNC;
  540.  
  541.         bp = bfind(bname, TRUE, 0);             /* First buffer         */
  542.         blistp = bfind("[List]", TRUE, BFINVS); /* Buffer list buffer   */
  543.         wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  544.         if (bp==NULL || wp==NULL || blistp==NULL)
  545.                 meexit(1);
  546.         curbp  = bp;                            /* Make this current    */
  547.         wheadp = wp;
  548.         curwp  = wp;
  549.         wp->w_wndp  = NULL;                     /* Initialize window    */
  550.         wp->w_bufp  = bp;
  551.         bp->b_nwnd  = 1;                        /* Displayed.           */
  552.         wp->w_linep = bp->b_linep;
  553.         wp->w_dotp  = bp->b_linep;
  554.         wp->w_doto  = 0;
  555.         for (cmark = 0; cmark < NMARKS; cmark++) {
  556.                 wp->w_markp[cmark] = NULL;
  557.                 wp->w_marko[cmark] = 0;
  558.         }
  559.         wp->w_toprow = 0;
  560. #if     COLOR
  561.         /* initalize colors to global defaults */
  562.         wp->w_fcolor = gfcolor;
  563.         wp->w_bcolor = gbcolor;
  564. #endif
  565.         wp->w_fcol = 0;
  566.         wp->w_ntrows = term.t_nrow-1;           /* "-1" for mode line.  */
  567.         wp->w_force = 0;
  568.         wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  569. }
  570. /*}}}*/
  571.  
  572. /*
  573.  * This is the general command execution routine. It handles the fake binding
  574.  * of all the keys to "self-insert". It also clears out the "thisflag" word,
  575.  * and arranges to move it to the "lastflag", so that the next command can
  576.  * look at it. Return the status of command.
  577.  */
  578. /*{{{  PASCAL NEAR execute(c, f, n)*/
  579. PASCAL NEAR execute(c, f, n)
  580.  
  581. {
  582.         register int status;
  583.         KEYTAB *key;                    /* key entry to execute */
  584.  
  585.         /* if the keystroke is a bound function...do it */
  586.         key = getbind(c);
  587.         if (key != NULL) {
  588.                 thisflag = 0;
  589.                 status = execkey(key, f, n);
  590.                 lastflag = thisflag;
  591.                 return(status);
  592.         }
  593.  
  594.         /*
  595.          * If a space was typed, fill column is defined, the argument is non-
  596.          * negative, wrap mode is enabled, and we are now past fill column,
  597.          * and we are not read-only, perform word wrap.
  598.          */
  599.         if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
  600.             n >= 0 && getccol(FALSE) > fillcol &&
  601.             (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
  602.                 execkey(&wraphook, FALSE, 1);
  603.  
  604.         if ((c>=0x20 && c<=0xFF)) {     /* Self inserting.      */
  605.                 if (n <= 0) {                   /* Fenceposts.          */
  606.                         lastflag = 0;
  607.                         return(n<0 ? FALSE : TRUE);
  608.                 }
  609.                 thisflag = 0;                   /* For the future.      */
  610.  
  611.                 /* if we are in overwrite mode, not at eol,
  612.                    and next char is not a tab or we are at a tab stop,
  613.                    delete a char forword                        */
  614.                 if (curwp->w_bufp->b_mode & MDOVER &&
  615.                     curwp->w_doto < curwp->w_dotp->l_used &&
  616.                         (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
  617.                          (curwp->w_doto) % tabsize == (tabsize - 1)))
  618.                                 ldelete(1L, FALSE, FALSE, FALSE);
  619.  
  620.                 /* do the appropriate insertion */
  621.                 if (c == '}' && (curbp->b_mode & MDCMOD) != 0)
  622.                         status = insbrace(n, c);
  623.                 else if (c == '#' && (curbp->b_mode & MDCMOD) != 0)
  624.                         status = inspound();
  625.                 else
  626.                         status = linsert(n, c, TRUE);
  627.  
  628. #if     CFENCE
  629.                 /* check for CMODE fence matching */
  630.                 if ((c == '}' || c == ')' || c == ']') &&
  631.                                 (curbp->b_mode & MDCMOD) != 0)
  632.                         fmatch(c);
  633. #endif
  634.  
  635.                 /* check auto-save mode */
  636.                 /* Don't autosave if we are in folds. MJB: 12-Oct-89 */
  637.                 if (curbp->b_mode & MDASAVE)
  638.                         if (--gacount == 0) {
  639.                                 if (curbp->b_nfolds == 0) {
  640.                                         /* and save the file if needed */
  641.                                         upscreen(FALSE, 0);
  642.                                         filesave(FALSE, 0);
  643.                                 }
  644.                                 else
  645.                                         mlwrite(TEXT238);
  646.                                         /* "%%Cannot AUTOSAVE when within entered fold" */
  647.  
  648.                                 gacount = gasave;
  649.                         }
  650.  
  651.                 lastflag = thisflag;
  652.                 return(status);
  653.         }
  654.         TTbeep();
  655.         mlwrite(TEXT19);                /* complain             */
  656. /*              "[Key not bound]" */
  657.         lastflag = 0;                           /* Fake last flags.     */
  658.         return(FALSE);
  659. }
  660. /*}}}*/
  661.  
  662. /*
  663.         Fancy quit command, as implemented by Norm. If the any buffer
  664. has changed do a write on that buffer and exit emacs, otherwise simply
  665. exit.
  666. */
  667.  
  668. /*{{{  PASCAL NEAR quickexit(f, n)*/
  669. PASCAL NEAR quickexit(f, n)
  670.  
  671. {
  672.         register BUFFER *bp;    /* scanning pointer to buffers */
  673.         register BUFFER *oldcb; /* original current buffer */
  674.         register int status;
  675.         WINDOW *oldwp;
  676.  
  677.         oldcb = curbp;                          /* save in case we fail */
  678.         oldwp = curwp;
  679.  
  680.         bp = bheadp;
  681.         while (bp != NULL) {
  682.                 if ((bp->b_flag&BFCHG) != 0     /* Changed.             */
  683.                 && (bp->b_flag&BFINVS) == 0) {  /* Real.                */
  684.                         curbp = bp;             /* make that buffer cur */
  685.                         curwp->w_bufp = bp;
  686.                         mlwrite(TEXT103,bp->b_fname);
  687. /*                              "[Saving %s]" */
  688.                         mlwrite("\n");
  689.                         if ((status = filesave(f, n)) != TRUE) {
  690.                                 curbp = oldcb;  /* restore curbp */
  691.                                 curwp = oldwp;
  692.                                 return(status);
  693.                         }
  694.                 }
  695.         bp = bp->b_bufp;                        /* on to the next buffer */
  696.         }
  697.         quit(f, n);                             /* conditionally quit   */
  698.         return(TRUE);
  699. }
  700. /*}}}*/
  701.  
  702. /*
  703.  * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  704.  * has been changed and not written out. Normally bound to "C-X C-C".
  705.  */
  706.  
  707. /*{{{  PASCAL NEAR quit(f, n)*/
  708. PASCAL NEAR quit(f, n)
  709.  
  710. {
  711.         register int status;    /* return status */
  712.  
  713.         if (f != FALSE          /* Argument forces it.  */
  714.         || anycb() == FALSE     /* All buffers clean or user says it's OK. */
  715.         || (status = mlyesno(TEXT104)) == TRUE) {
  716. /*                           "Modified buffers exist. Leave anyway" */
  717. #if     FILOCK
  718.                 if (lockrel() != TRUE) {
  719.                         TTputc('\n');
  720.                         TTputc('\r');
  721.                         TTclose();
  722.                         TTkclose();
  723.                         status = meexit(1);
  724.                 }
  725. #endif
  726.                 if (f)
  727.                         status = meexit(n);
  728.                 else
  729.                         status = meexit(GOOD);
  730.         }
  731.         mlerase();
  732.         return(status);
  733. }
  734. /*}}}*/
  735.  
  736. /*{{{  PASCAL NEAR meexit(status)*/
  737. PASCAL NEAR meexit(status)
  738. int status;     /* return status of emacs */
  739. {
  740.         eexitflag = TRUE;       /* flag a program exit */
  741.         eexitval = status;
  742.  
  743.         /* and now.. we leave and let the main loop kill us */
  744.         return(TRUE);
  745. }
  746. /*}}}*/
  747.  
  748. /*
  749.  * Begin a keyboard macro.
  750.  * Error if not at the top level in keyboard processing. Set up variables and
  751.  * return.
  752.  */
  753.  
  754. /*{{{  PASCAL NEAR ctlxlp(f, n)*/
  755. PASCAL NEAR ctlxlp(f, n)
  756.  
  757. {
  758.         if (kbdmode != STOP) {
  759.                 mlwrite(TEXT105);
  760. /*                      "%%Macro already active" */
  761.                 return(FALSE);
  762.         }
  763.         mlwrite(TEXT106);
  764. /*              "[Start macro]" */
  765.         kbdptr = &kbdm[0];
  766.         kbdend = kbdptr;
  767.         kbdmode = RECORD;
  768.         return(TRUE);
  769. }
  770. /*}}}*/
  771.  
  772. /*
  773.  * End keyboard macro. Check for the same limit conditions as the above
  774.  * routine. Set up the variables and return to the caller.
  775.  */
  776.  
  777. /*{{{  PASCAL NEAR ctlxrp(f, n)*/
  778. PASCAL NEAR ctlxrp(f, n)
  779.  
  780. {
  781.         if (kbdmode == STOP) {
  782.                 mlwrite(TEXT107);
  783. /*                      "%%Macro not active" */
  784.                 return(FALSE);
  785.         }
  786.         if (kbdmode == RECORD) {
  787.                 mlwrite(TEXT108);
  788. /*                      "[End macro]" */
  789.                 kbdmode = STOP;
  790.         }
  791.         return(TRUE);
  792. }
  793. /*}}}*/
  794.  
  795. /*
  796.  * Execute a macro.
  797.  * The command argument is the number of times to loop. Quit as soon as a
  798.  * command gets an error. Return TRUE if all ok, else FALSE.
  799.  */
  800.  
  801. /*{{{  PASCAL NEAR ctlxe(f, n)*/
  802. PASCAL NEAR ctlxe(f, n)
  803.  
  804. {
  805.         if (kbdmode != STOP) {
  806.                 mlwrite(TEXT105);
  807. /*                      "%%Macro already active" */
  808.                 return(FALSE);
  809.         }
  810.         if (n <= 0)
  811.                 return(TRUE);
  812.         kbdrep = n;             /* remember how many times to execute */
  813.         kbdmode = PLAY;         /* start us in play mode */
  814.         kbdptr = &kbdm[0];      /*    at the beginning */
  815.         return(TRUE);
  816. }
  817. /*}}}*/
  818.  
  819. /*
  820.  * Abort.
  821.  * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  822.  * Sometimes called as a routine, to do general aborting of stuff.
  823.  */
  824.  
  825. /*{{{  PASCAL NEAR ctrlg(f, n)*/
  826. PASCAL NEAR ctrlg(f, n)
  827.  
  828. {
  829.         TTbeep();
  830.         kbdmode = STOP;
  831.         mlwrite(TEXT8);
  832. /*              "[Aborted]" */
  833.         return(ABORT);
  834. }
  835. /*}}}*/
  836.  
  837. /* tell the user that this command is illegal while we are in
  838.    VIEW (read-only) mode                                */
  839.  
  840. /*{{{  PASCAL NEAR rdonly()*/
  841. PASCAL NEAR rdonly()
  842.  
  843. {
  844.         TTbeep();
  845.         mlwrite(TEXT109);
  846. /*              "[Key illegal in VIEW mode]" */
  847.         return(FALSE);
  848. }
  849. /*}}}*/
  850.  
  851. /*{{{  PASCAL NEAR resterr()*/
  852. PASCAL NEAR resterr()
  853.  
  854. {
  855.         TTbeep();
  856.         mlwrite(TEXT110);
  857. /*              "[That command is RESTRICTED]" */
  858.         return(FALSE);
  859. }
  860. /*}}}*/
  861.  
  862.       /* user function that does NOTHING */
  863.  
  864. /*{{{  PASCAL NEAR nullproc(f, n)*/
  865. PASCAL NEAR nullproc(f, n)
  866.  
  867. int n, f;       /* yes, these are default and never used.. but MUST be here */
  868.  
  869. {
  870. }
  871. /*}}}*/
  872.  
  873.   /* set META prefixing pending */
  874.  
  875. /*{{{  PASCAL NEAR meta(f, n)*/
  876. PASCAL NEAR meta(f, n)
  877.  
  878. {
  879.         prefix |= META;
  880.         prenum = n;
  881.         predef = f;
  882.         return(TRUE);
  883. }
  884. /*}}}*/
  885.  
  886.   /* set ^X prefixing pending */
  887.  
  888. /*{{{  PASCAL NEAR cex(f, n) */
  889. PASCAL NEAR cex(f, n) 
  890.  
  891. {
  892.         prefix |= CTLX;
  893.         prenum = n;
  894.         predef = f;
  895.         return(TRUE);
  896. }
  897. /*}}}*/
  898.  
  899.     /* dummy function for binding to universal-argument */
  900.  
  901. /*{{{  PASCAL NEAR unarg() */
  902. PASCAL NEAR unarg() 
  903. {
  904. }
  905. /*}}}*/
  906.  
  907. /*      bytecopy:       copy a string...with length restrictions
  908.                         ALWAYS null terminate
  909. */
  910.  
  911. /*{{{  char *PASCAL NEAR bytecopy(dst, src, maxlen)*/
  912. char *PASCAL NEAR bytecopy(dst, src, maxlen)
  913.  
  914. char *dst;      /* destination of copied string */
  915. char *src;      /* source */
  916. int maxlen;     /* maximum length */
  917.  
  918. {
  919.         char *dptr;     /* ptr into dst */
  920.  
  921.         dptr = dst;
  922.         while (*src && (maxlen-- > 0))
  923.                 *dptr++ = *src++;
  924.         *dptr = 0;
  925.         return(dst);
  926. }
  927. /*}}}*/
  928.  
  929. /*****          Compiler specific Library functions     ****/
  930.  
  931. #if     RAMSIZE
  932. /*{{{  */
  933. /*      These routines will allow me to track memory usage by placing
  934.         a layer on top of the standard system malloc() and free() calls.
  935.         with this code defined, the environment variable, $RAM, will
  936.         report on the number of bytes allocated via malloc.
  937.  
  938.         with SHOWRAM defined, the number is also posted on the
  939.         end of the bottom mode line and is updated whenever it is changed.
  940. */
  941.  
  942. #undef  malloc
  943. #undef  free
  944.  
  945. char *allocate(nbytes)  /* allocate nbytes and track */
  946.  
  947. unsigned nbytes;        /* # of bytes to allocate */
  948.  
  949. {
  950.         char *mp;       /* ptr returned from malloc */
  951.         char *malloc();
  952.         FILE *track;    /* malloc track file */
  953.  
  954.         mp = malloc(nbytes);
  955.  
  956. #if     RAMTRCK
  957.         track = fopen("malloc.dat", "a");
  958.         fprintf(track, "Allocating %u bytes at %u:%u\n", nbytes,
  959.                         FP_SEG(mp), FP_OFF(mp));
  960.         fclose(track);
  961. #endif
  962.  
  963.         if (mp) {
  964. #if     0
  965.                 envram += nbytes;
  966. #else
  967.                 envram += 1;
  968. #endif
  969. #if     RAMSHOW
  970.                 dspram();
  971. #endif
  972.         }
  973.  
  974.         return(mp);
  975. }
  976.  
  977. release(mp)     /* release malloced memory and track */
  978.  
  979. char *mp;       /* chunk of RAM to release */
  980.  
  981. {
  982.         unsigned *lp;   /* ptr to the long containing the block size */
  983. #if     RAMTRCK
  984.         FILE *track;    /* malloc track file */
  985.  
  986.         track = fopen("malloc.dat", "a");
  987.         fprintf(track, "Freeing %u:%u\n",
  988.                         FP_SEG(mp), FP_OFF(mp));
  989.         fclose(track);
  990. #endif
  991.  
  992.         if (mp) {
  993.                 /* update amount of ram currently malloced */
  994. #if     0
  995.                 lp = ((unsigned *)mp) - 1;
  996.                 envram -= (long)*lp - 2;
  997. #else
  998.                 envram -= 1;
  999. #endif
  1000.                 free(mp);
  1001. #if     RAMSHOW
  1002.                 dspram();
  1003. #endif
  1004.         }
  1005. }
  1006.  
  1007. #if     RAMSHOW
  1008. dspram()        /* display the amount of RAM currently malloced */
  1009.  
  1010. {
  1011.         char mbuf[20];
  1012.         char *sp;
  1013.  
  1014.         TTmove(term.t_nrow - 1, 70);
  1015. #if     COLOR
  1016.         TTforg(7);
  1017.         TTbacg(0);
  1018. #endif
  1019.         sprintf(mbuf, "[%lu]", envram);
  1020.         sp = &mbuf[0];
  1021.         while (*sp)
  1022.                 TTputc(*sp++);
  1023.         TTmove(term.t_nrow, 0);
  1024.         movecursor(term.t_nrow, 0);
  1025. }
  1026. #endif
  1027. /*}}}*/
  1028. #endif
  1029.